#include "app_bt.h"
#include <string.h>
#include "app_serial.h"
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include "log.h"

/**
 *   把字节数组转换为蓝牙数据
   * 准备向设备写前处理数据来满足蓝牙发送数据的要求
 * 当前data: conn_type id_len msg_len id msg (01 02 03 ff ff 11 22 33)
 * 蓝牙发送数据格式:  41 54 2b 4d 45 53 48 00 ff ff 11 22 33 0d 0a
  示例：41 54 2b 4d 45 53 48 00 ff ff 11 22 33 0d 0a
        41 54 2b 4d 45 53 48 00： AT+MESH（固定头部）
        ff ff: 对端的MADDR（如果是FFFF代表群发）
        11 22 33: 要发送的数据（不超过12字节）
        0d 0a：\r\n（固定结尾）`

 */
static char write_header[8] = {0x41, 0x54, 0x2b, 0x4d, 0x45, 0x53, 0x48, 0x00};
static char write_tailer[2] = {0x0d, 0x0a};
static int app_bt_pre_write(char *write_data, int write_data_len)
{
    // 1  提取 id msg
    int id_len = write_data[1];
    int msg_len = write_data[2];
    char id[id_len];
    char msg[msg_len];
    memcpy(id, write_data + 3, id_len);
    memcpy(msg, write_data + 3 + id_len, msg_len);
    // 2 拼接数据
    memcpy(write_data, write_header, 8);                        // 帧头
    memcpy(write_data + 8, id, id_len);                         // id
    memcpy(write_data + 8 + id_len, msg, msg_len);              // msg
    memcpy(write_data + 8 + id_len + msg_len, write_tailer, 2); // 帧尾

    int len = 8 + id_len + msg_len + 2;
    return len;
}

/**
 *  读后预处理
 *
 * 读取蓝牙中的数据  转换为 字节数组
 *
 * 从设备读取数据后处理数据来满足网关应用的要求
 * 接收方得到数据1（4）：ok\r\n
 * 接收方得到数据2（3 + [2]）：f1 dd 07 23 23 ff ff 41 42 43
    f1 dd : 固定的头部
    07： 之后数据的长度（5-16之间）
    23 23：对端（发送方）的MADDR  // id
    ff ff: 我的MADDR或ffff(群发) //网关id
    41 42 43：发送的数据   //msg
    步骤 ：
    0 准备一个buff
    1 读取到数据后要先写入buff
    2 尝试判断是否够一个整帧数据
    3  buff 中是否包含帧头数据  f1 dd
    4   把帧头以前的数据全部清理 改长度
    5  buff 中数据是否长度达到最小的整帧长度 8 ?
    6  提取数据长度（第三位） ，判断是否缓冲区有整帧数据
    7  如果 有
          7.1  提取 id  msg
          7.2  拼接为字节数据格式
          7.3  清理buff中的这帧数据，改长度
    8   返回数据长度

*/
static char temp_buff[100];
static int data_len = 0;
static char read_header[2] = {0xf1, 0xdd};

static void remove_data(int remove_len)
{
    memmove(temp_buff, temp_buff + remove_len, data_len - remove_len); // 后面数据前移覆盖
    data_len -= remove_len;                                            // 数据长度减去
}

static int app_bt_post_read(char *write_data, int write_data_len)
{
    // 1 读取到数据后要先写入buff
    memcpy(temp_buff + data_len, write_data, write_data_len);
    data_len += write_data_len;
    // 2 尝试判断是否够一个整帧数据
    // 3  buff 中是否包含帧头数据  f1 dd
    for (size_t i = 0; i < data_len - 1; i++)
    {
        if (temp_buff[i] == read_header[0] && temp_buff[i + 1] == read_header[1])
        { // 找到帧头
            // 4   把帧头以前的数据全部清理 改长度
            remove_data(i);
            // 5  buff 中数据是否长度达到最小的整帧长度 8 ?
            if (data_len < 8)
            {
                return 0;
            }
            // 6  提取数据长度（第三位） ，判断是否缓冲区有整帧数据
            int real_data_len = temp_buff[2] + 3;
            if (data_len < real_data_len)
            {
                return 0;
            }
            // 7 如果 有 长度够一个整帧数据
            //       7.1  提取 id  msg
            int id_len = 2;                  // 在蓝牙是id固定长度
            int msg_len = real_data_len - 7; // 7 = 帧头2+长度1+对端id2+本端id2；
            char id[2];
            memcpy(id, temp_buff + 3, id_len);
            char msg[msg_len];
            memcpy(msg, temp_buff + 7, msg_len);
            //       7.2  拼接为字节数据格式
            write_data[0] = conn_type_ble;
            write_data[1] = id_len;
            write_data[2] = msg_len;
            memcpy(write_data + 3, id, id_len);
            memcpy(write_data + 3 + id_len, msg, msg_len);
            int final_data_len = 3 + id_len + msg_len;

            //       7.3  清理buff中的这帧数据，改长度
            remove_data(real_data_len);

            return final_data_len;
        }
    }
    return 0;
}

static int app_bt_ack(int fd)
{
    char buff[4];
    read(fd, buff, 4);
    if (memcmp(buff, "OK\r\n", 4) == 0)
    {
        return 0;
    }
    else
    {
        return -1;
    }
}

/**
 * @brief 测试蓝牙模块
 * @return 0  成功  -1 失败
 * 步骤：1  发送AT
 *      2  接收回复 OK\r\n
 *
 */
static int app_bt_status(int fd)
{
    // * 步骤：1  发送AT
    write(fd, "AT\r\n", 4);
    usleep(50 * 1000);
    // *  2  接收回复 OK\r\n
    return app_bt_ack(fd);
}

/**
 * @brief 测试蓝牙模块
 * @return 0  成功  -1 失败
 * 步骤：1  发送AT
 *      2  接收回复 OK\r\n
 *
 */
static int app_bt_set_baudrate(int fd, BT_BAUD_RATE baudrate)
{
    //     发送AT指令
    char cmd[32] = {0};
    sprintf(cmd, "AT+BAUD%c\r\n", baudrate);
    write(fd, cmd, 10);
    usleep(50 * 1000);
    return 0;
}

// 网络名
static int app_bt_set_name(int fd, char *name)
{
    //     发送AT指令
    char cmd[32] = {0};
    sprintf(cmd, "AT+NAME%s\r\n", name);
    write(fd, cmd, strlen(cmd));
    usleep(50 * 1000);
    return 0;
}

// netid
static int app_bt_set_netid(int fd, char *netid)
{
    //     发送AT指令
    char cmd[32] = {0};
    sprintf(cmd, "AT+NETID%s\r\n", netid);
    write(fd, cmd, strlen(cmd));
    usleep(50 * 1000);
    return 0;
}

// maddr
static int app_bt_set_maddr(int fd, char *maddr)
{
    //     发送AT指令
    char cmd[32] = {0};
    sprintf(cmd, "AT+MADDR%s\r\n", maddr);
    write(fd, cmd, strlen(cmd));
    usleep(50 * 1000);
    return 0;
}

// reset
static int app_bt_reset(int fd)
{
    //     发送AT指令
    char cmd[32] = {0};
    sprintf(cmd, "AT+RESET\r\n");
    write(fd, cmd, strlen(cmd));
    return 0;
}

//   给  蓝牙超级模块设置默认参数
// 1 发送AT指令 进行测试
// 1.1 改为非阻塞模式
//  1.2  发送AT 指令进行测试
//  2  如果不通过  要对超级模块进行波特率设置 当前为9600
//   2.1 把当前串口波特率降为9600
//     2.2  再次进行测试 如果不通过  蓝牙模块有问题（更换）
//      2.3 如果通过  把蓝牙模块设为115200
//     2.4  把蓝牙模块进行reset
//      2.5 串口在调会115200   flush 生效
//      2.6  再次进行测试 如果不通过 蓝牙模块有问题（更换）
//  3  如果通过   模块进行波特率当115200
//  4  设置其他参数 netid  name  maddr
//  5  串口恢复为阻塞模式
static int app_bt_init_config_default(int fd)
{
    // 1 发送AT指令 进行测试
    // 1.1 改为非阻塞模式
    app_serial_isblock(fd, 0);
    tcflush(fd, TCIOFLUSH);
    //  1.2  发送AT 指令进行测试
    if (app_bt_status(fd) == -1)
    {
        //    2  如果不通过  要对超级模块进行波特率设置 当前为9600
        //     2.1 把当前串口波特率降为9600
        app_serial_set_baudrate(fd, BR_9600);
        tcflush(fd, TCIOFLUSH);
        //     2.2  再次进行测试 如果不通过  蓝牙模块有问题（更换）
        if (app_bt_status(fd) == -1)
        {
            log_fatal(" 蓝牙模块可能存在硬件问题尝试更换 9600!!");
            return -1;
        }
        //      2.3 如果通过  把蓝牙模块设为115200
        app_bt_set_baudrate(fd, BT_BAUD_115200);
        //     2.4  把蓝牙模块进行reset
        app_bt_reset(fd);
        sleep(1);//等待重启完成
        //      2.5 串口再调回115200   flush 生效
        app_serial_set_baudrate(fd, BR_115200);
        tcflush(fd, TCIOFLUSH);
        //      2.6  再次进行测试 如果不通过 蓝牙模块有问题（更换）
        if (app_bt_status(fd) == -1)
        {
            log_fatal(" 蓝牙模块可能存在硬件问题尝试更换 115200 !!");
            return -1;
        }
    }
    //  3  如果通过   模块进行波特率当115200
    log_info("串口和蓝牙模块波特率协调一致115200");

    //  4  设置其他参数 netid  name  maddr
    app_bt_set_name(fd, "atguigu");
    app_bt_set_netid(fd, "1234");
    app_bt_set_maddr(fd, "0077");
    //  5  串口恢复为阻塞模式
    app_serial_isblock(fd, 1);
    tcflush(fd, TCIOFLUSH);
    log_info("设置蓝牙模块配置成功！！");
    return 0;
}

/**
 * @brief 为设备进行蓝牙初始化
 *  1  对蓝牙模块进行初始化配置（网段 地址 名称 波特率）
 *  2  设置蓝牙数据的预处理方法
 *     2.1 写前预处理
 *     2.2 读后预处理
 */
int app_bt_init(app_device_t *device)
{
    int ret= app_bt_init_config_default(device->dev_fd);
    if(ret==-1)
    {
        log_error("app_bt_init_config_default error");
        return -1;
    }

    device->pre_write = app_bt_pre_write;
    device->post_read = app_bt_post_read;
    return 0;
}